import json
import math
import os.path
import queue
import threading
import time
import datetime
from pathlib import Path

import pymodbus.client.sync
import  requests
from fastapi import  FastAPI
import struct

#-----------------------------
# install modbus libs
# pip3 install -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple  pymodbus==2.5.3  --低版本
#-----------------------------
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import serial, serial.tools.list_ports
import py104client

class TDecoder:
    def __init__(self):
        pass
    @staticmethod
    def decode(var , regs , exInfo=None):
        status = 0
        value = 0
        try:
            funType = var['funType']
            if funType=='Bit':
                status , value = TDecoder.decodeBit(var , regs , exInfo)
            elif funType=='U16':
                status , value = TDecoder.decodeU16(var , regs , exInfo)
            elif funType=='I16':
                status , value = TDecoder.decodeI16(var , regs , exInfo)
            elif funType=='U32':
                status , value = TDecoder.decodeU32(var , regs , exInfo)
            elif funType=='I32':
                status , value = TDecoder.decodeI32(var , regs , exInfo)
            elif funType=='I32LH':
                status , value = TDecoder.decodeI32LH(var , regs , exInfo)
            elif funType=='U64':
                status , value = TDecoder.decodeU64(var , regs , exInfo)
            elif funType=='I64':
                status , value = TDecoder.decodeI64(var , regs , exInfo)
            elif funType=='U32Time':
                status , value = TDecoder.decodeU32Time(var , regs , exInfo)
            elif funType=='Float32Big':
                status , value = TDecoder.decodeFloat32Big(var , regs , exInfo)
            elif funType=='PGU':
                status , value = TDecoder.decodePgu(var , regs , exInfo)
            else:
                print('decode error:' , var , regs)
        except Exception as er:
            print(er)
        return  status , value
    @staticmethod
    def decodeBit(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            bitStart = var['bitStart']
            mask = 0x01 << bitStart
            v1 = regs[0] & mask
            if v1==0 :
                res = 0
            else:
                res = 1
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodeU16(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            res = regs[0]
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodeI16(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            v = regs[0]
            if v< 0x7fff:
                res = v
            else:
                res = -1*( (v ^ 0xffff) + 1 )
                #res =  -1 * ( (~v) + 1)
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodeU32(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            vH = regs[0]
            vL = regs[1]
            res = (vH << 16 ) + vL
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodeI32(var , regs , exInfo=None):
        status = 0
        res = 0
        try:

            vH = regs[0]
            vL = regs[1]
            v = (vH << 16 ) + vL
            if vH < 0x7fff :
                res = v
            else:
                res = -1 * ( ( v ^ 0xffffffff) +1  )
                #res =  -1 * (  (~v) + 1)
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodeI32LH(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            vL = regs[0]
            vH = regs[1]
            v = (vH << 16 ) + vL
            if vH < 0x7fff :
                res = v
            else:
                res = -1 * ( ( v ^ 0xffffffff) +1  )
                #res =  -1 * (  (~v) + 1)
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodeU64(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            v0 = regs[2]
            v1 = regs[3]
            v2 = regs[0]
            v3 = regs[1]
            v = v0<<48 + v1<<32 + v2<<16 + v3
            res = v
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodeI64(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            v0 = regs[2]
            v1 = regs[3]
            v2 = regs[0]
            v3 = regs[1]
            v = v0<<48 + v1<<32 + v2<<16 + v3
            if v0 < 0x7fff:
                res = v
            else:
                res = -1 * ( ( v ^ 0xffffffffffffffff) +1  )
                #res =  -1 * (  (~v) + 1)
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    def decodeFloat32Big(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            vH = regs[0]
            vL = regs[1]
            bytes = bytearray([vH//256, vH%256, vL//256, vL%256])
            v0 =  struct.unpack('!f', bytes)
            res = 0.01 * int (v0[0]*100)
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodePgu(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            bitStart = var['bitStart']
            bitLen = var['bitLen']
            if bitLen == 1 :
                res = regs[bitStart]
            elif bitLen == 2 :
                res = (regs[bitStart]<<16) + regs[bitStart+1]
            status = 1
        except Exception as er:
            print(er)
        return  status , res
    @staticmethod
    def decodeU32Time(var , regs , exInfo=None):
        status = 0
        res = 0
        try:
            rH = regs[0]
            rL = regs[1]
            varValue = (rH << 16 ) + rL
            varValue = varValue - 8 * 3600
            res =  varValue
            #varDisp = (datetime.datetime.fromtimestamp(varValue)).strftime("%Y-%m-%d %H:%M:%S")
            status = 1
        except Exception as er:
            print(er)
        return  status , res
class TPyUtils:
    def __init__(self):
        pass
    @staticmethod
    def connectModbusRtu(comPort="COM1" , comBaudrate = 9600 , comStopBit = 1 , comParity='E' , comDataBit= 8 ):
        res = None
        try:
            client = ModbusClient(
                method="rtu" ,
                port= comPort , baudrate=comBaudrate , stopbits=comStopBit, parity= comParity, bytesize=comDataBit ,
                strict= False,
                timeout= 2
                )
            client.connect()
            res = client
        except Exception as er:
            print(er)
        return  res
class TPyTerValue:
    def __init__(self):
        self.varKey = ""
        self.varId  = 0
        self.regs=[]
        self.srcValue = 0
        self.v0 = 0
        self.v1 = 0
        self.tm = 0
        self.disp = ""
        self.postSuccess = 0
    def checkChanged(self , srcValue , changePer ):
        res = False
        try:
            if self.tm == 0 :
                res = True
            else :
                if srcValue != self.v1 :
                    if changePer==0:
                        res = True
                    else :
                        if self.v1 ==0 :
                            res = True
                        else:
                            dlt = abs(srcValue - self.v1)
                            per = dlt/abs(self.v1)
                            if per > changePer:
                                res = True
        except Exception as er:
            print(er)
        return res
    def setValue(self , srcValue , value , tm , disp , regs):
        try:
            self.v0 = self.v1
            self.v1 = value
            self.srcValue = srcValue
            self.tm = tm
            self.disp = disp
            self.regs = regs
        except Exception as er:
            print(er)
    def getJson(self ):
        return {
            'k': self.varKey ,
            'id': self.varId ,
            't': self.tm ,
            'v': self.v1 ,
            'd': self.disp ,
            'v0': self.v0 ,
            'regs': self.regs
        }

class TPy645Client:
    def __init__(self):
        self.comPort = 'COM8'
        self.comBaudrate = 1200
        self.comParity = 'E'  # serial.PARITY_EVEN ,
        self.comTimeout = 2
        self.serial = serial.Serial()

    def isOpen(self):
        res = False
        try:
            if self.serial != None:
                res = self.serial.isOpen()
        except Exception as er:
            print(er)
        return res
    def open(self):
        try:
            if not self.isOpen():
                self.serial = serial.Serial(
                    self.comPort, self.comBaudrate, parity=self.comParity, timeout=self.comTimeout
                )
        except Exception as er:
            print(er)
        return self.isOpen()
    def close(self):
        try:
            if self.serial != None:
                if self.serial.isOpen():
                    self.serial.close()
                self.serial = None
        except Exception as er:
            print(er)

    def readValue(self, address, dataFlag):
        status = 0
        minus = 0
        res = ''
        try:
            sendBytes = self.getSendBytes(address, dataFlag)
            self.serial.write(sendBytes)
            time.sleep(0.2)
            #recData = list(self.serial.readline())
            recData = list(self.serial.readall())
            i =0
            resBytes=[]
            recFlag = False
            while i<len(recData) :
                if recData[i] == 0x68:
                    resBytes = recData[i:]
                    recFlag = True
                    break
                i = i +1

            if recFlag :
                print('rec 645 bytes:' , resBytes)
                endByte = resBytes[-3]
                minusFlag = dataFlag in ['0122','0222','0322','0032','0042','0062']
                if minusFlag and endByte > 0x7f :
                    print('--------> minus endByte' , endByte )
                    try:
                        minus = 1
                        endByte = endByte & 0x7f
                        resBytes[-3] = endByte
                    except Exception as erMinus :
                        print('minus error.' ,erMinus )
                try:
                    dataBytes = ["{:0>2d}".format(int(hex(x - 0x33).replace('0x', ''))) for x in resBytes[14:-2]]
                    dataBytes.reverse()
                    res = "".join(dataBytes)
                except Exception as erDeco:
                    print('erDecode error' , erDeco)
                if minus>0 :
                    res = str(-1 * int(res))
                status = 1
        except Exception as er:
            print('read 645 error.',er, resBytes[14:-2] , dataFlag)
        return status, res
    def getSendBytes(self, address, dataFlag):
        res = []
        try:
            res.append(0x68)
            for i in range(6):
                pos = (6 - (i + 1)) * 2
                addr = int(address[pos:pos + 2])
                addr = (addr // 10) * 16 + addr % 10
                res.append(addr)
            res.append(0x68)
            res.append(0x11)
            res.append(0x04)
            for i in range(4):
                di = int(dataFlag[i]) + 0x33
                res.append(di)
            c = 0
            for i in res:
                c = c + i
                c = c % 256
            res.append(c)
            res.append(0x16)
        except Exception as er:
            print(er)
        return bytearray(res)
class TPyTerBus:
    def __init__(self):
        self.ter = None
        self.busCode = ""
        self.client = None
        self.running = False
        #  优先执行的临时任务
        self.priTaskQueue = queue.Queue()
        self.scheduleTasks = []
        self.scheduleTaskIndex = 0
        self.dictChangedVarValues = {}
        self.executeThread = None

    def star(self):
        try:
            self.connectClient()
            connectFlag = self.clientIsConnected()
            if connectFlag :
                self.running = True
                self.executeThread = threading.Thread( target=self.executeHandler , daemon= True)
                self.executeThread.start()
        except Exception as er:
            print(er)
    def stop(self):
        try:
            self.running = False
            self.disconnectClient()
            if self.client!=None :
                self.client = None
        except Exception as er:
            print(er)
    def restartBus(self):
        try:
            self.stop()
            self.star()
        except Exception as er:
            print(er)
    def executeHandler(self):
        try:
            self.scheduleTasks = self.getScheduleTasks()
            self.scheduleTaskIndex = 0
            while self.running and  self.clientIsConnected():
                try:
                    task = self.getCurentTask()
                    if task == None:
                        time.sleep(1)
                    else:
                        self.executeTask(task)
                except Exception as eer:
                    print(eer)
            self.stop()
        except Exception as er:
            print(er)

    # protected methods
    def connectClient(self):
        try:
            pass
        except Exception as er:
            print(er)
    def disconnectClient(self):
        res = False
        try:
            pass
        except Exception as er:
            print(er)
        return  res
    def clientIsConnected(self):
        res = True
        try:
            pass
        except Exception as er:
            print(er)
        return  res
    def getScheduleTasks(self):
        res =[]
        try:
            pass
        except Exception as er:
            print(er)
        return  res
    def getCurentTask(self):
        currentTask = None
        try:
            pass
        except Exception as er:
            print(er)
        return currentTask
    def executeTask(self , task):
        try:
            pass
        except Exception as er:
            print(er)
class TPyTerBusModbusRtu(TPyTerBus):
    def __init__(self):
        super().__init__()
        self.afterWaitTime = 0

    # protected methods
    def clientIsConnected(self):
        res = True
        try:
            res = self.client!=None
        except Exception as er:
            print(er)
        return  res
    def connectClient(self):
        try:
            self.disconnectClient()
            busInfo = self.ter.info["buses"][self.busCode]
            comPort = busInfo['com_port']
            comBaudrate = busInfo['com_baudrate']
            comStopBit = busInfo['com_stopbits']
            comParity = busInfo['com_parity']
            comDataBit = busInfo['com_bytesize']
            client=None
            if comPort.find('dev/') >=0 :
                self.afterWaitTime = 1

                client = pymodbus.client.sync.ModbusSerialClient(method='rtu', port=comPort, baudrate=comBaudrate, parity=comParity,
                                      stopbits=comStopBit, bytesize=comDataBit, retry_on_empty=True, timeout=14 , strict=True)
                print('modbusRtu params:')
                print(comPort , comBaudrate , comParity , comStopBit , comDataBit)
                #client = TPyUtils.connectModbusRtu(comPort , comBaudrate , comStopBit , comParity , comDataBit ,retry_on_empty=True , timeout=14)
            else:
                client = TPyUtils.connectModbusRtu(comPort , comBaudrate , comStopBit , comParity , comDataBit)
            connFlag = client.connect()
            if connFlag :
                print('connect success' , busInfo['busCode'] , comPort)
            else:
                print('connect faild' , busInfo['busCode'] , comPort)
            self.client = client
        except Exception as er:
            print(er)
    def disconnectClient(self):
        try:
            if self.client!=None:
                try:
                    self.client.close()
                except Exception as ee:
                    print(ee)
                self.client = None
        except Exception as er:
            print(er)
    def getScheduleTasks(self):
        res =[]
        try:
            tasks = {}
            for v in  self.ter.info["variables"].values():
                varKey = v['varKey']
                busCode = v['busCode']
                if busCode == self.busCode :
                    unitId = v['unitId']
                    regStart = v['regStart']
                    regLen = v['regLen']
                    duration = v['duration']
                    if duration == None :
                        duration = -1
                    taskKey = busCode+"_"+str(unitId)+"_"+str(regStart)
                    task = None
                    if taskKey in tasks.keys():
                        task = tasks[taskKey]
                    else:
                        task = TPyTask()
                        task.bus = self
                        task.taskKey = taskKey
                        task.busCode = self.busCode
                        task.regStart = regStart
                        task.unitId = unitId
                    if regLen> task.regLen :
                        task.regLen = regLen
                    if duration< task.duration or task.duration<0:
                        task.duration = duration
                    task.varKeys.append(varKey)
                    tasks[taskKey]  = task
            res = list(tasks.values())
            tasks = None
        except Exception as er:
            print(er)
        return  res
    def getCurentTask(self):
        currentTask = None
        try:
            if self.priTaskQueue.empty():
                tSize = len(self.scheduleTasks)
                if tSize >0 :
                    if self.scheduleTaskIndex >= tSize:
                        self.scheduleTaskIndex = 0
                    task = self.scheduleTasks[self.scheduleTaskIndex]
                    self.scheduleTaskIndex = self.scheduleTaskIndex + 1
                    currentTask = task
            else:
                currentTask = self.priTaskQueue.get()
        except Exception as er:
            print(er)
        return currentTask
    def executeTask(self , task):
        try:
            time.sleep(0.01)
            if task.function == 'r' :
                if task.isTimeout():
                    task.lastTm = time.time()
                    regStart = task.regStart
                    regLen = task.regLen
                    unitId = task.unitId

                    if regStart in [0, 1000]:
                        time.sleep(0.5)
                    elif regStart in [35300, 35304]:
                        time.sleep(1)
                        print('reg 3530X')
                    if self.afterWaitTime >0 :
                        time.sleep(self.afterWaitTime)
                    result = self.client.read_holding_registers(regStart, regLen, unit=unitId)


                    #if task.varKeys[0]=='var$1116':
                    #    print(task)
                    if result.isError():
                        print('collect faild', unitId ,  regStart , regLen, result)
                        time.  sleep(1)
                    else:
                        regs = list(result.registers)
                        if regStart==1000:
                            print('collect success', unitId ,  regStart , regLen, regs)
                        self.ter.setVarRegists(self.busCode ,  task.varKeys ,  regs)
                if (self.scheduleTaskIndex +1) ==len(self.scheduleTasks):
                    self.ter.onBusLoop(self.busCode)
        except Exception as er:
            print(er)
class TPyTerBusModbusHw(TPyTerBus):
    def __init__(self):
        super().__init__()
        self.afterWaitTime = 0
        print('load hw modbus ...')

    # protected methods
    def clientIsConnected(self):
        res = True
        try:
            if self.client!=None  :
                res = self.client.isOpen()
        except Exception as er:
            print(er)
        return  res
    def connectClient(self):
        try:
            self.disconnectClient()
            busInfo = self.ter.info["buses"][self.busCode]
            comPort = busInfo['com_port']
            comBaudrate = busInfo['com_baudrate']
            comStopBit = busInfo['com_stopbits']
            comParity = busInfo['com_parity']
            comDataBit = busInfo['com_bytesize']
            client=None
            if comPort.find('dev/') >=0 :
                self.afterWaitTime = 1
                print(' com port:' , comPort)
                client =  serial.Serial( comPort , comBaudrate , timeout=4)
                print(client)
            else:
                client = serial.Serial( comPort , comBaudrate , timeout=4)
            connFlag = client.isOpen()
            if connFlag :
                print('connect success' , busInfo['busCode'] , comPort)
            else:
                print('connect faild' , busInfo['busCode'] , comPort)
            self.client = client
        except Exception as er:
            print(er)
    def disconnectClient(self):
        try:
            if self.client!=None:
                try:
                    self.client.close()
                except Exception as ee:
                    print(ee)
                self.client = None
        except Exception as er:
            print(er)
    def getScheduleTasks(self):
        res =[]
        try:
            tasks = {}
            for v in  self.ter.info["variables"].values():
                varKey = v['varKey']
                busCode = v['busCode']
                if busCode == self.busCode :
                    unitId = v['unitId']
                    regStart = v['regStart']
                    regLen = v['regLen']
                    duration = v['duration']
                    if duration == None :
                        duration = -1
                    taskKey = busCode+"_"+str(unitId)+"_"+str(regStart)
                    task = None
                    if taskKey in tasks.keys():
                        task = tasks[taskKey]
                    else:
                        task = TPyTask()
                        task.bus = self
                        task.taskKey = taskKey
                        task.busCode = self.busCode
                        task.regStart = regStart
                        task.unitId = unitId
                    if regLen> task.regLen :
                        task.regLen = regLen
                    if duration< task.duration or task.duration<0:
                        task.duration = duration
                    task.varKeys.append(varKey)
                    tasks[taskKey]  = task
            res = list(tasks.values())
            tasks = None
        except Exception as er:
            print(er)
        return  res
    def getCurentTask(self):
        currentTask = None
        try:
            if self.priTaskQueue.empty():
                tSize = len(self.scheduleTasks)
                if tSize >0 :
                    if self.scheduleTaskIndex >= tSize:
                        self.scheduleTaskIndex = 0
                    task = self.scheduleTasks[self.scheduleTaskIndex]
                    self.scheduleTaskIndex = self.scheduleTaskIndex + 1
                    currentTask = task
            else:
                currentTask = self.priTaskQueue.get()
        except Exception as er:
            print(er)
        return currentTask
    def crc16(self , datas):
        crc =0
        crcH=0
        crcL=0
        try:
            crc = 0xFFFF
            # 循环处理每个数据字节
            for byte in datas:
                # 将每个数据字节与crc进行异或操作
                crc ^= byte

                # 对crc的每一位进行处理
                for _ in range(8):
                    # 如果最低位为1，则右移一位并执行异或0xA001操作(即0x8005按位颠倒后的结果)
                    if crc & 0x0001:
                        crc = (crc >> 1) ^ 0xA001
                    # 如果最低位为0，则仅将crc右移一位
                    else:
                        crc = crc >> 1
                crcL = crc % 256
                crcH = crc >> 8
        except Exception as er:
            print('crc error',er)
        return crc , crcH , crcL
    def executeTask(self , task):
        try:
            time.sleep(0.01)
            if task.function == 'r' :
                if task.isTimeout():
                    task.lastTm = time.time()
                    regStart = task.regStart
                    regLen = task.regLen
                    unitId = task.unitId
                    regs=[]
                    regAddrH = regStart>>8
                    regAddrL = regStart % 256
                    sendList = [unitId , 0x03 , regAddrH ,  regAddrL , 0 ,  regLen ]

                    print('-------------------  task --------------')
                    print('send list' , sendList)
                    crc , crcH , crcL = self.crc16(sendList)
                    sendList = sendList + [crcL , crcH]
                    sendBytes =bytearray(sendList)
                    self.client.flushInput()
                    self.client.flushOutput()
                    sendLen = self.client.write(sendBytes)
                    print('send bytes (',sendLen,')',[hex(x) for x in sendBytes])
                    time.sleep(1)
                    recvList = []
                    while self.client.inWaiting()>0:
                        try:
                            recvList = recvList + list(self.client.read(self.client.inWaiting()))
                        except Exception as erRead:
                            print(erRead)
                        time.sleep(2)
                    recLen = len(recvList)
                    print('rec len:', recLen)
                    print(recvList)
                    if recLen>= 5:
                        try:
                            for i in range(recLen):
                                if recvList[i]== unitId and recvList[i+1]==0x03 and recvList[i+2] == regLen*2 :
                                    pos = i+3
                                    for k in range( regLen):
                                        vh = recvList[ pos ]
                                        vl = recvList[ pos + 1]
                                        v = (vh<<8) + vl
                                        print('decode value', vh , vl , v )
                                        regs.append(v)
                                        pos = pos + 2
                                    break
                                    print('regs' , regs)
                        except Exception as erDecode:
                            print('decode data error')
                            print(erDecode)
                        if len(regs) >0:
                            self.ter.setVarRegists(self.busCode ,  task.varKeys ,  regs)
                            print('regs:' , regs)
                    print('-----------------',self.scheduleTaskIndex,'/',len(self.scheduleTasks), self.busCode,'-----------------------')
                    self.ter.onBusLoop(self.busCode)
                if (self.scheduleTaskIndex +1) ==len(self.scheduleTasks):
                    print('*************  post hw data *******************')
                    self.ter.onBusLoop(self.busCode)
        except Exception as er:
            print(er)
class TPyTerBus645(TPyTerBus):
    def __init__(self):
        super().__init__()
    # protected methods
    def clientIsConnected(self):
        res = True
        try:
            res = self.client!=None and self.client.isOpen()
        except Exception as er:
            print(er)
        return  res
    def connectClient(self):
        try:
            self.disconnectClient()
            busInfo = self.ter.info['buses'][self.busCode]
            comPort = busInfo['com_port']
            comBaudrate = busInfo['com_baudrate']
            comParity = busInfo['com_parity']
            client = TPy645Client()
            client.comPort = comPort
            client.comBaudrate = comBaudrate
            client.comParity = comParity
            self.client = client
            self.client.open()
        except Exception as er:
            print(er)
    def disconnectClient(self):
        try:
            if self.client != None:
                if self.client.isOpen():
                    self.client.close()
                self.client = None
        except Exception as er:
            print(er)
    def getScheduleTasks(self):
        res =[]
        try:
            tasks = {}
            for v in  self.ter.info["variables"].values():
                varKey = v['varKey']
                busCode = v['busCode']
                if busCode == self.busCode :

                    addr645 = v['addr645']
                    dataFlag = v['varCode']
                    duration = v['duration']
                    if duration == None :
                        duration = -1
                    taskKey = busCode+"_"+str(addr645)+"_"+str(dataFlag)
                    task = None
                    if taskKey in tasks.keys():
                        task = tasks[taskKey]
                    else:
                        task = TPyTask()
                        task.bus = self
                        task.taskKey = taskKey
                        task.busCode = self.busCode
                        task.addr645 = addr645
                        task.dataFlag645 = dataFlag
                    if duration< task.duration or task.duration<0:
                        task.duration = duration
                    task.varKeys.append(varKey)
                    tasks[taskKey]  = task
            res = list(tasks.values())
            tasks = None
        except Exception as er:
            print(er)
        return  res
    def getCurentTask(self):
        currentTask = None
        try:
            if self.priTaskQueue.empty():
                tSize = len(self.scheduleTasks)
                if tSize >0 :
                    if self.scheduleTaskIndex >= tSize:
                        self.scheduleTaskIndex = 0
                    task = self.scheduleTasks[self.scheduleTaskIndex]
                    self.scheduleTaskIndex = self.scheduleTaskIndex + 1
                    currentTask = task
            else:
                currentTask = self.priTaskQueue.get()
        except Exception as er:
            print(er)
        return currentTask
    def executeTask(self , task):
        try:
            time.sleep(0.1)
            if task.function == 'r' :
                if task.isTimeout():
                    task.lastTm = time.time()
                    dataFlag = task.dataFlag645
                    addr645 = task.addr645
                    status , valueStr= self.client.readValue( addr645 , dataFlag)
                    print('------------',self.busCode, addr645 , dataFlag, valueStr,'-------------')

                    if status == 1 :
                        self.ter.setVarRegists(self.busCode, task.varKeys, [ valueStr ])
                if (self.scheduleTaskIndex +1) ==len(self.scheduleTasks):
                    self.ter.onBusLoop(self.busCode)
        except Exception as er:
            print(er)
class TPyTerBus101(TPyTerBus):
    def __init__(self):
        super().__init__()
class TPyTerBus104(TPyTerBus):
    def __init__(self):
        super().__init__()
        self.client = py104client.TIce645Client()
    # protected methods
    def star(self):
        try:
            self.stop()
            busInfo = self.ter.info['buses'][self.busCode]
            self.client.host = busInfo['host']
            self.client.port = busInfo['port']
            self.running = True
            self.executeThread = threading.Thread( target=self.client.start , daemon= True)
            self.executeThread.start()
        except Exception as er:
            print(er)
    def stop(self):
        try:
            self.running = False
            if self.client!=None :
                self.client.stop()
                self.client = None
        except Exception as er:
            print(er)

class TPyTerBusLiyangTimer(TPyTerBus):
    def __init__(self):
        super().__init__()
        self.connected = False
        self.duration = 3600
        self.lastTime = 0
        self.apiUrl = "http://hh.hhdata.cn:31563/zntdb/query"
        self.varList = [{"varKey":"var$1159","varId":1159,"varCode":"year_down","varDesc":"年下网电量"},{"varKey":"var$1160","varId":1160,"varCode":"year_up","varDesc":"年上网电量"},{"varKey":"var$1161","varId":1161,"varCode":"year_generate","varDesc":"年总发电量"},{"varKey":"var$1162","varId":1162,"varCode":"year_used","varDesc":"年消耗电量"},{"varKey":"var$1163","varId":1163,"varCode":"month_down","varDesc":"月下网电量"},{"varKey":"var$1164","varId":1164,"varCode":"month_up","varDesc":"月上网电量"},{"varKey":"var$1165","varId":1165,"varCode":"month_generate","varDesc":"月总发电量"},{"varKey":"var$1166","varId":1166,"varCode":"month_used","varDesc":"月消耗电量"},{"varKey":"var$1167","varId":1167,"varCode":"month_totalPf","varDesc":"月功率因数"},{"varKey":"var$1168","varId":1168,"varCode":"day_down","varDesc":"日下网电量"},{"varKey":"var$1169","varId":1169,"varCode":"day_up","varDesc":"日上网电量"},{"varKey":"var$1170","varId":1170,"varCode":"day_generate","varDesc":"日总发电量"},{"varKey":"var$1171","varId":1171,"varCode":"day_used","varDesc":"日消耗电量"}]
        self.varKeys=[]
        self.varValues ={}
        for v in self.varList:
            vk = v['varKey']
            self.varKeys.append(vk)
            self.varValues[vk] = 0
    # protected methods
    def clientIsConnected(self):
        res = True
        try:
            res = self.connected
        except Exception as er:
            print(er)
        return  res
    def connectClient(self):
        try:
            self.disconnectClient()
            self.connected = True
        except Exception as er:
            print(er)
    def disconnectClient(self):
        try:
            self.connected = False
        except Exception as er:
            print(er)
    def getScheduleTasks(self):
        res =[]
        try:
            pass
        except Exception as er:
            print(er)
        return  res
    def getCurentTask(self):
        currentTask = None
        try:
            currentTask ={}
        except Exception as er:
            print(er)
        return currentTask
    def executeTask(self , task):
        try:
            while self.connected :
                try:
                    time.sleep(1)
                    nowTm = time.time()
                    timeout = (nowTm - self.lastTime) > self.duration
                    if timeout :
                        print('liyang timer running...')
                        self.lastTime = nowTm
                        dtEndTime = datetime.datetime.now()
                        self.runHandler(dtEndTime)
                except Exception as ee:
                    print(ee)
        except Exception as er:
            print(er)
    def runHandler(self , dtEndTime):
        try:

            # declare
            # dtEndTime = datetime.datetime.now()
            dlt = datetime.timedelta(hours=8)
            utcEndTime = dtEndTime - dlt
            strEndTm = utcEndTime.strftime("%Y-%m-%dT%H:%M:%SZ")
            dtYear = datetime.datetime(dtEndTime.year , 1 , 1)
            utcYear = dtYear - dlt
            strFromYearTm = utcYear.strftime("%Y-%m-%dT%H:%M:%SZ")
            dtMonth = datetime.datetime(dtEndTime.year , dtEndTime.month , 1)
            utcMonth = dtMonth - dlt
            strFromMonthTm = utcMonth.strftime("%Y-%m-%dT%H:%M:%SZ")
            dtDay = datetime.datetime(dtEndTime.year , dtEndTime.month , dtEndTime.day)
            utcDay = dtDay - dlt
            strFromDayTm = utcDay.strftime("%Y-%m-%dT%H:%M:%SZ")
            print( strFromYearTm , strFromMonthTm , strFromDayTm , strEndTm)

            # query
            sqlLiyangPower = "tdb/liyangPower"
            yearDown , yearMinDown , yearMaxDown , yearStatus = self.queryMinMaxValue(sqlLiyangPower , '1118' , strFromYearTm , strEndTm)
            yearUp ,yearMinUp , yearMaxUp , yearStatus = self.queryMinMaxValue(sqlLiyangPower , '1119' , strFromYearTm , strEndTm)
            yearGen1 , yearMinGen1 , yearMaxGen1 , yearStatus = self.queryMinMaxValue(sqlLiyangPower , '1113' , strFromYearTm , strEndTm)
            yearGen2 , yearMinGen2 , yearMaxGen2 , yearStatus = self.queryMinMaxValue(sqlLiyangPower , '1114' , strFromYearTm , strEndTm)
            yearGen3 , yearMinGen3 , yearMaxGen3 , yearStatus = self.queryMinMaxValue(sqlLiyangPower , '1115' , strFromYearTm , strEndTm)
            yearGen4 , yearMinGen4 , yearMaxGen4 , yearStatus = self.queryMinMaxValue(sqlLiyangPower , '1116' , strFromYearTm , strEndTm)
            yearGen = yearGen1 + yearGen2 + yearGen3 + yearGen4
            yearPay = yearGen + yearDown - yearUp

            monthDown , monthMinDown , monthMaxDown , monthStatus = self.queryMinMaxValue(sqlLiyangPower , '1118' , strFromMonthTm , strEndTm)
            monthUp ,  monthMinUp , monthMaxUp , monthStatus = self.queryMinMaxValue(sqlLiyangPower , '1119' , strFromMonthTm , strEndTm)
            monthGen1 , monthMinGen1 , monthMaxGen1 , monthStatus = self.queryMinMaxValue(sqlLiyangPower , '1113' , strFromMonthTm , strEndTm)
            monthGen2 , monthMinGen2 , monthMaxGen2 , monthStatus = self.queryMinMaxValue(sqlLiyangPower , '1114' , strFromMonthTm , strEndTm)
            monthGen3 , monthMinGen3 , monthMaxGen3 , monthStatus = self.queryMinMaxValue(sqlLiyangPower , '1115' , strFromMonthTm , strEndTm)
            monthGen4 , monthMinGen4 , monthMaxGen4 , monthStatus = self.queryMinMaxValue(sqlLiyangPower , '1116' , strFromMonthTm , strEndTm)
            monthGen = monthGen1 + monthGen2 + monthGen3 + monthGen4
            monthPay = monthGen + monthDown - monthUp
            monthQs = 0.01 * int(monthDown *100 /math.sqrt(monthDown*monthDown + monthUp*monthUp))

            dayDown , dayMinDown , dayMaxDown , dayStatus = self.queryMinMaxValue(sqlLiyangPower , '1118' , strFromDayTm , strEndTm)
            dayUp , dayMinUp , dayMaxUp , dayStatus = self.queryMinMaxValue(sqlLiyangPower , '1119' , strFromDayTm , strEndTm)
            dayGen1 , dayMinGen1 , dayMaxGen1 , dayStatus = self.queryMinMaxValue(sqlLiyangPower , '1113' , strFromDayTm , strEndTm)
            dayGen2 , dayMinGen2 , dayMaxGen2 , dayStatus = self.queryMinMaxValue(sqlLiyangPower , '1114' , strFromDayTm , strEndTm)
            dayGen3 , dayMinGen3 , dayMaxGen3 , dayStatus = self.queryMinMaxValue(sqlLiyangPower , '1115' , strFromDayTm , strEndTm)
            dayGen4 , dayMinGen4 , dayMaxGen4 , dayStatus = self.queryMinMaxValue(sqlLiyangPower , '1116' , strFromDayTm , strEndTm)
            dayGen = dayGen1 + dayGen2 + dayGen3 + dayGen4
            dayPay = dayGen + dayDown - dayUp

            def setFloat( f):
                r=0
                try:
                    r = 0.01 *int(100*f)
                except Exception as er :
                    print(er)
                return  r
            
            # post variables
            self.varValues['var$1159'] = setFloat( yearDown)
            self.varValues['var$1160'] = setFloat( yearUp)
            self.varValues['var$1161'] = setFloat( yearGen)
            self.varValues['var$1162'] = setFloat( yearPay)
            self.varValues['var$1163'] = setFloat( monthDown)
            self.varValues['var$1164'] = setFloat( monthUp)
            self.varValues['var$1165'] = setFloat( monthGen)
            self.varValues['var$1166'] = setFloat( monthPay)
            self.varValues['var$1167'] = setFloat( monthQs)
            self.varValues['var$1168'] = setFloat( dayDown)
            self.varValues['var$1169'] = setFloat( dayUp)
            self.varValues['var$1170'] = setFloat( dayGen)
            self.varValues['var$1171'] = setFloat( dayPay)

            self.ter.setVarRegists(self.busCode ,  self.varKeys ,  [] , self.varValues)
            self.ter.onBusLoop(self.busCode)

        except Exception as er:
            print(er)
    def queryMinMaxValue(self , dataKey , varId , fromTm , endTm):
        vDiff = 0
        vMin =0
        vMax = 0
        status = 0
        try:

            headers = {
                'Content-Type': 'application/json',
            }
            postData = {
                "tdbCode":"znTdb",
                "dbKey": dataKey,
                "queryPs":{
                    "varId": varId ,
                    "fromTm": fromTm ,
                    "endTm": endTm
                }
            }
            postSuccess = False
            try:
                postUrl = self.apiUrl
                resp = requests.post(url=postUrl, headers=headers, json=postData)
                if resp.status_code == 200:
                    respObj = resp.json()
                    if respObj['status']==1  and 'result' in respObj.keys() and len(respObj['result']) >0 and 'series' in respObj['result'][0].keys():
                        series = respObj['result'][0]['series']
                        values = series[0]['values'][0]
                        vDiff = values[1]
                        vMin = values[2]
                        vMax = values[3]
                        status = 1
                        print( varId , fromTm , endTm , vDiff , vMin , vMax)
                    else:
                        status = 1003
                else:
                    print('post data faild.')
            except Exception as eerr:
                print('disconnect ')
                print(eerr)
        except Exception as er:
            print(er)
        return vDiff, vMin , vMax , status
class TPyTerBusWuxiTimer(TPyTerBus):
    def __init__(self):
        super().__init__()
        self.connected = False
        self.duration = 3600
        self.lastTime = 0
        self.apiUrl = "http://hh.hhdata.cn:31563/zntdb/query"
        self.varList = [{"varKey":"var$1688","varId":1688,"varCode":"year_generate","varDesc":"年总发电量"},{"varKey":"var$1689","varId":1689,"varCode":"month_generate","varDesc":"月总发电量"},{"varKey":"var$1690","varId":1690,"varCode":"day_generate","varDesc":"日总发电量"}]
        self.varKeys=[]
        self.varValues ={}
        for v in self.varList:
            vk = v['varKey']
            self.varKeys.append(vk)
            self.varValues[vk] = 0
    # protected methods
    def clientIsConnected(self):
        res = True
        try:
            res = self.connected
        except Exception as er:
            print(er)
        return  res
    def connectClient(self):
        try:
            self.disconnectClient()
            self.connected = True
        except Exception as er:
            print(er)
    def disconnectClient(self):
        try:
            self.connected = False
        except Exception as er:
            print(er)
    def getScheduleTasks(self):
        res =[]
        try:
            pass
        except Exception as er:
            print(er)
        return  res
    def getCurentTask(self):
        currentTask = None
        try:
            currentTask ={}
        except Exception as er:
            print(er)
        return currentTask
    def executeTask(self , task):
        try:
            while self.connected :
                try:
                    time.sleep(1)
                    nowTm = time.time()
                    timeout = (nowTm - self.lastTime) > self.duration
                    if timeout :
                        print('wuxi timer running...')
                        self.lastTime = nowTm
                        dtEndTime = datetime.datetime.now()
                        self.runHandler(dtEndTime)
                except Exception as ee:
                    print(ee)
        except Exception as er:
            print(er)
    def runHandler(self , dtEndTime):
        try:

            # declare
            # dtEndTime = datetime.datetime.now()
            dlt = datetime.timedelta(hours=8)
            utcEndTime = dtEndTime - dlt
            strEndTm = utcEndTime.strftime("%Y-%m-%dT%H:%M:%SZ")
            dtYear = datetime.datetime(dtEndTime.year , 1 , 1)
            utcYear = dtYear - dlt
            strFromYearTm = utcYear.strftime("%Y-%m-%dT%H:%M:%SZ")
            dtMonth = datetime.datetime(dtEndTime.year , dtEndTime.month , 1)
            utcMonth = dtMonth - dlt
            strFromMonthTm = utcMonth.strftime("%Y-%m-%dT%H:%M:%SZ")
            dtDay = datetime.datetime(dtEndTime.year , dtEndTime.month , dtEndTime.day)
            utcDay = dtDay - dlt
            strFromDayTm = utcDay.strftime("%Y-%m-%dT%H:%M:%SZ")
            print('wuxi-terminal-time', strFromYearTm , strFromMonthTm , strFromDayTm , strEndTm)

            # query
            sqlLiyangPower = "tdb/liyangPower"
            yearGen , yearMinGen , yearMaxGen , yearStatus = self.queryMinMaxValue(sqlLiyangPower , '1677' , strFromYearTm , strEndTm)
            monthGen , monthMinGen , monthMaxGen , monthStatus = self.queryMinMaxValue(sqlLiyangPower , '1677' , strFromMonthTm , strEndTm)
            dayGen , dayMinGen , dayMaxGen , dayStatus = self.queryMinMaxValue(sqlLiyangPower , '1677' , strFromDayTm , strEndTm)
            # post variables

            def setFloat( f):
                r=0
                try:
                    r = 0.01 *int(100*f)
                except Exception as er :
                    print(er)
                return  r
            self.varValues['var$1688'] = setFloat(yearGen)
            self.varValues['var$1689'] = setFloat(monthGen)
            self.varValues['var$1690'] =setFloat( dayGen)

            self.ter.setVarRegists(self.busCode ,  self.varKeys ,  [] , self.varValues)
            self.ter.onBusLoop(self.busCode)

        except Exception as er:
            print(er)
    def queryMinMaxValue(self , dataKey , varId , fromTm , endTm):
        vDiff = 0
        vMin =0
        vMax = 0
        status = 0
        try:

            headers = {
                'Content-Type': 'application/json',
            }
            postData = {
                "tdbCode":"znTdb",
                "dbKey": dataKey,
                "queryPs":{
                    "varId": varId ,
                    "fromTm": fromTm ,
                    "endTm": endTm
                }
            }
            postSuccess = False
            try:
                postUrl = self.apiUrl
                resp = requests.post(url=postUrl, headers=headers, json=postData)
                if resp.status_code == 200:
                    respObj = resp.json()
                    if respObj['status']==1  and 'result' in respObj.keys() and len(respObj['result']) >0 and 'series' in respObj['result'][0].keys():
                        series = respObj['result'][0]['series']
                        values = series[0]['values'][0]
                        vDiff = values[1]
                        vMin = values[2]
                        vMax = values[3]
                        status = 1
                        print( varId , fromTm , endTm , vDiff , vMin , vMax)
                    else:
                        status = 1003
                else:
                    print('post data faild.')
            except Exception as eerr:
                print('disconnect ')
                print(eerr)
        except Exception as er:
            print(er)
        return vDiff, vMin , vMax , status
class TPyTask:
    def __init__(self):
        self.bus = None
        self.taskType = 'schedule'
        self.function = 'r'
        self.taskKey = ""
        self.terCode = ""
        self.busCode=""
        self.unitId = 0
        self.regStart = 0
        self.regLen = 0
        self.varKeys=[]
        self.lastTm = 0
        self.duration = -1
        self.dataFlag645 =""
        self.addr645 = ""
        self.exInfo ={}
        self.AfterWaitTime = 0

    def isTimeout(self):
        res = False
        try:
            if self.varKeys[0]=='var$147':
                pass

            tn = time.time()
            res = (tn - self.lastTm) > self.duration
        except Exception as er:
            print(er)
        return  res

class TPyTerminal:
    def __init__(self):
        self.defaultSettings = {
            "terCode" : "ter_liyanng_01",
            "localPort": 10083 ,
            "dataUrl" : "http://hh.hhdata.cn:31563/zn/getTerData",
            "postUrl" : "http://hh.hhdata.cn:31563/zn/varPost"
        }
        self.settings ={
            "terCode":"" ,
            "localPort": 10083 ,
            "infoApiUrl":"",
            "postApiUrl":""
        }
        self.info = {
            "terInfo":"",
            "buses":{},
            "devices":{},
            "variables":{}
        }
        self.buses ={}
        self.varValues ={}
    def setSettings(self , _terCode):
        try:
            settings = {}
            appPath = self.getAppDataPath()
            settingFn = appPath / "settings.txt"
            if os.path.exists(settingFn):
                with open(settingFn , 'r' ) as f :
                    try:
                        content = f.read()
                        settings = json.loads(content)
                    except Exception as err:
                        print(err)
            else:
                settings= json.loads(json.dumps(self.defaultSettings))
            if _terCode!="":
                settings['terCode'] = _terCode
            self.settings = settings
            with open(settingFn , 'w' , encoding='utf-8') as f :
                content = json.dumps(settings)
                f.write(content)
        except Exception as er :
            print(er)
    def loadInfo(self ):
        try:
            infoFn = self.getAppDataPath() / "info.txt"
            #update info from server
            try:
                terCode = self.settings['terCode']
                dataUrl = self.settings["dataUrl"]+"?terCode="+ terCode
                print('load config datas .' , dataUrl , '>>' , infoFn)
                rs = requests.get(dataUrl)
                if rs.status_code == 200 :
                    objs = json.loads(rs.content)
                    if objs['status'] ==1 :
                        with open(infoFn , 'w' , encoding='utf-8') as f :
                            f.write(rs.text)
                    print('update sys info.')
            except Exception as erUpdate:
                print(erUpdate)
            #load info from local
            try:
                if os.path.exists(infoFn) :
                    objs = None
                    with open(infoFn , 'r' , encoding='utf-8') as f:
                        try:
                            content = f.read()
                            objs = json.loads(content)
                        except Exception as eer:
                            print('load local info fail')
                            print(eer)
                    if objs!=None:
                        self.info['terInfo'] = objs['data']['terInfo']
                        self.info['buses'] = objs['data']['buses']
                        self.info['devices'] = objs['data']['devices']
                        self.info['variables'] = objs['data']['vars']
                        for v in self.info['variables'].values():
                            varValue = TPyTerValue()
                            varValue.varKey = v['varKey']
                            varValue.varId = v['varId']
                            self.varValues[varValue.varKey] = varValue
            except Exception as erLoad:
                print(erLoad)
        except Exception as er :
            print(er)
    def getAppDataPath(self):
        res = ""
        try:
            curPath = Path(os.path.dirname(__file__))
            appDataPath = curPath.parent / "appdatas"
            if not appDataPath.exists():
                appDataPath.mkdir(mode=0x777, parents=True , exist_ok=True)
            res = appDataPath.absolute() / ""
        except Exception as er :
            print(er)
        return  res
    def restart(self):
        try:
            self.reset()
            self.loadInfo()
            for busCode  in self.info['buses'].keys():
                bus = self.getBus(busCode)
                if bus !=None :
                    bus.restartBus()
        except Exception as er:
            print(er)
    def reset(self):
        try:
            self.info = {
                "terInfo": {},
                "buses":{},
                "devices":{},
                "variables":{}
            }
            for bus in self.buses.values():
                bus.stop()
                bus = None
            self.buses ={}
            self.varValues ={}
        except Exception as er:
            print(er)
    def getBus(self , busCode):
        bus = None
        try:
            if busCode in self.info['buses'].keys():
                if busCode in self.buses.keys():
                    bus = self.buses[busCode]
                else:
                    protocolType = self.info['buses'][busCode]['protocolType']
                    if protocolType=='modbusRtu':
                        bus = TPyTerBusModbusRtu()
                    elif protocolType=='hwRtu':
                        bus = TPyTerBusModbusHw()
                    elif protocolType=='645':
                        bus = TPyTerBus645()
                    elif protocolType=='101':
                        bus = TPyTerBus101()
                    elif protocolType=='104':
                        bus = TPyTerBus104()
                    elif protocolType=='LiYangTimer':
                        bus = TPyTerBusLiyangTimer()
                    elif protocolType=='WuXiTimer':
                        bus = TPyTerBusWuxiTimer()
                    if bus != None:
                        bus.ter = self
                        bus.busCode = busCode
                        self.buses[busCode] = bus
        except Exception as er :
            print(er)
        return  bus
    def restartBus(self , busCode ):
        res = 0
        try:
            bus = self.getBus(busCode)
            if bus== None:
                bus.restart()
                res = 1 
            else:
                res = -1000

        except Exception as er :
            print(er)
        return  res
    def setVarRegists(self , busCode ,  varKeys , regs , varValues={}):
        res = 0
        try:
            protocol = self.info['buses'][busCode]['protocolType']
            bus = self.buses[busCode]
            for varKey in varKeys:
                try:
                    var = self.info['variables'][varKey]
                    decodeFlag = False
                    srcValue = 0

                    if protocol=='modbusRtu' or protocol=='hwRtu':
                        status , value = TDecoder.decode(var , regs )
                        if status == 1 :
                            srcValue = value
                            decodeFlag = True
                    elif protocol=='645':
                        if len(regs)>0:
                            srcValue = float(regs[0])
                            decodeFlag = True
                    elif protocol=='LiYangTimer':
                        srcValue = varValues[varKey]
                        decodeFlag = True
                        regs=[srcValue]
                    elif protocol=='WuXiTimer':
                        srcValue = varValues[varKey]
                        decodeFlag = True
                        regs=[srcValue]


                    if decodeFlag :
                        varValueObj = self.varValues[varKey]
                        nowTm = time.time()
                        changePer = 0
                        if var['varType'] =='a' :
                            changePer = 0.005
                        if var ['varId'] == 1116:
                            pass
                            #print('var1116')
                        changedFlag = varValueObj.checkChanged(srcValue , changePer )
                        if protocol=='LiYangTimer':
                            changedFlag = True
                        if changedFlag :
                            varValueObj.tm = nowTm
                            rate = var['rate']
                            rate1 = var['rate1']
                            decLen = var['decLen']
                            unit = var['varUnit']
                            value = srcValue
                            if rate != 1 :
                                value = value * rate
                            if rate1 != 1 :
                                value = value * rate1
                            if decLen ==0 :
                                value = int(value)
                            elif decLen == 1  :
                                value = 0.1 * int(10*value)
                            elif decLen == 2  :
                                value = 0.01 * int(100*value)
                            elif decLen == 3  :
                                value = 0.001 * int(1000*value)
                            elif decLen == 4  :
                                value = 0.0001 * int(10000*value)
                            disp = str(value)
                            if var["funType"] == 'U32Time':
                                disp = (datetime.datetime.fromtimestamp(value)).strftime("%Y-%m-%d %H:%M:%S")
                            if unit !='' :
                                disp = disp + ' ' + unit
                            varValueObj.setValue(
                                srcValue = srcValue,
                                value = value,
                                tm = nowTm,
                                disp = disp,
                                regs = regs
                            )
                            bus.dictChangedVarValues[varKey] = varValueObj
                except Exception as erDecode:
                    print('set var value faild.',busCode ,  varKeys , regs , varValues , var)
                    print(erDecode)

        except Exception as er :
            print(er)
        return  res
    def onBusLoop(self , busCode  ):
        try:
            bus = self.buses[busCode]
            if busCode=='busWx01_WuxiTimer':
                print('post device' , bus.dictChangedVarValues.keys())
            if len(bus.dictChangedVarValues.keys())>0:
                headers = {
                    'Content-Type': 'application/json',
                }
                varData = [ x.getJson()  for x in bus.dictChangedVarValues.values()]
                postData = {
                    "vars": varData
                }
                postSuccess = False
                try:
                    resp = requests.post(url=self.settings["postUrl"], headers=headers, json=postData)
                    if resp.status_code == 200:
                        postSuccess = True
                    else:
                        print('post data faild.')
                except Exception as eerr:
                    print('disconnect ')
                    print(eerr)
                self.saveLog(bus  , varData , postSuccess)
                bus.dictChangedVarValues={}
        except Exception as er :
            print(er)
    def saveLog(self , bus , varDatas , postSuccess= True):
        try:
            content = "\n".join([json.dumps(x) for x in varDatas])
            tm = time.time()
            fn = datetime.datetime.now().strftime("%Y%m%d")+".txt"
            logPath = self.getAppDataPath() / ("logs/"+bus.busCode)
            if not os.path.exists(logPath):
                Path(logPath).mkdir(mode=0x777 , parents=True, exist_ok=True)
            logFn = logPath / fn
            with open(logFn , mode='a' , encoding='utf-8') as f :
                f.writelines(content)
            if not postSuccess:
                unPostPath = self.getAppDataPath() / ("unpost/"+bus.busCode)
                if not os.path.exists(unPostPath):
                    Path(unPostPath).mkdir(mode=0x777 , parents=True, exist_ok=True)
                logFn = unPostPath / fn
                with open(logFn , mode='a' , encoding='utf-8') as f :
                    f.writelines(content)
        except Exception as er :
            print(er)

ter = TPyTerminal()
app = FastAPI()

@app.get("/")
async def root():
    return {
        'action':"root" ,
        "version":"iot-terminal-20241207"
    }

@app.get("/info")
async def info():
    return  ter.info
@app.get("/values")
async def info():
    res = [ x.getJosn() for x in ter.varValues]
    return  res



